# -*- coding: utf-8 -*-
# Python中默认的编码格式是 ASCII 格式，在没修改编码格式时无法正确打印汉字，所以在读取中文时会报错。

# Python通过yield提供了对协程的基本支持，但是不完全。而第三方的gevent为Python提供了比较完善的协程支持。
# gevent是第三方库，通过greenlet实现协程，其基本思想是：
# 当一个greenlet遇到IO操作时，比如访问网络，就自动切换到其他的greenlet，等到IO操作完成，再在适当的时候切换回来继续执行。
# 由于IO操作非常耗时，经常使程序处于等待状态，有了gevent为我们自动切换协程，就保证总有greenlet在运行，而不是等待IO。
# 由于切换是在IO操作时自动完成，所以gevent需要修改Python自带的一些标准库，这一过程在启动时通过monkey patch完成


# 因为python线程的性能问题，在python中使用多线程运行代码经常不能达到预期的效果。
# 而有些时候我们的逻辑中又需要开更高的并发，或者简单的说，就是让我们的代码跑的更快，
# 在同样时间内执行更多的有效逻辑、减少无用的等待。gevent就是一个现在很火、支持也很全面的python第三方协程库。
# gevent是python的一个并发框架，以微线程greenlet为核心，使用了epoll事件监听机制以及诸多其他优化而变得高效。
# 而且其中有个monkey类，将现有基于Python线程直接转化为greenlet(类似于打patch)。在运行时的具体流程大概就是：
# 当一个greenlet遇到IO操作时，比如访问网络/睡眠等待，就自动切换到其他的greenlet，
# 等到IO操作完成，再在适当的时候切换回来继续执行。
# 由于IO操作非常耗时，经常使程序处于等待状态，有了gevent为我们自动切换协程，
# 就保证总有greenlet在运行，而不是等待IO。同时也因为只有一个线程在执行，会极大的减少上下文切换的成本。

# https://www.jianshu.com/p/bb6c7f9aa1ae


from gevent import monkey; monkey.patch_all()
import gevent
import requests
from datetime import datetime


def f(url):
    print ('time: %s, GET: %s' % (datetime.now(), url))
    resp = requests.get(url)
    print ('time: %s, %d bytes received from %s.' % (
        datetime.now(), len(resp.text), url))


gevent.joinall([
        gevent.spawn(f, 'https://www.python.org/'),
        gevent.spawn(f, 'https://www.yahoo.com/'),
        gevent.spawn(f, 'https://github.com/'),
])


# 由上图可以看出，程序基本在同一时间触发了对三个网站的请求，然后各自进行，分别结束。
# 也就是当gevent发现阻塞之后，让当前急需执行，然后自动切换到了另外的请求中运行。